/*
 * BAT_Validator.c
 *
 * Data structure validator for BAT.
 *
 * $Id: BAT_Validator.c 927 2006-09-03 06:17:24Z rpz $
 *
 * Bob Zimmermann <rpz@cse.wustl.edu> Totally free.
 *
 */

#include "BAT_Validator.h"
#include "BAT_Factory.h"

char **_BAT_Validator_get_argv(BAT_Validator * v, char *cmdline, int *argc);
void _BAT_Validator_free_argv(BAT_Validator * v, int argc, char **argv);

BAT_Validator *
BAT_Validator_new()
{
  BAT_Validator *v;
  BAT_Factory *fac;
  darray_t *plugins;
  BAT_Validate_Plugin *plugin;
  BAT_Sub_Validator_Handle *h;
  da_pos_t i, sz;

  v = malloc(sizeof(BAT_Validator));
  v->bat = NULL;
  /* v->gene = NULL; v->tx = NULL; v->feat = NULL; */

  v->handles = darray_new(5, darray_ops_new(NULL, NULL, NULL, mem_free));

  fac = BAT_Factory_new();
  plugins = BAT_Factory_get_validate_plugins(fac);
  sz = darray_size(plugins);
  for (i = 0; i < sz; i++) {
    plugin = darray_get(plugins, i);

    h = malloc(sizeof(BAT_Sub_Validator_Handle));
    h->plugin = plugin;
    h->obj = plugin->construct();
    darray_add(v->handles, h);
  }
  BAT_Factory_delete(fac, 1);

  return v;
}

void
BAT_Validator_delete(BAT_Validator * v, int befrei)
{
  da_pos_t i, sz;
  BAT_Sub_Validator_Handle *h;
  sz = darray_size(v->handles);
  if (v->handles != NULL) {
    for (i = 0; i < sz; i++) {
      h = darray_get(v->handles, i);
      h->plugin->delete(h->obj, 1);
    }
    darray_delete(v->handles, 1);
  }

  if (befrei)
    free(v);
}

int
BAT_Validator_add_command(BAT_Validator * v, char *cmd)
{
  char **argv;
  int argc, stat;
  da_pos_t i, sz;
  BAT_Sub_Validator_Handle *h, *the_h;

  sz = darray_size(v->handles);

  /* make a local copy of cmd, since it might be in non-editable memory */
  argv = _BAT_Validator_get_argv(v, cmd, &argc);

  for (i = 0, the_h = NULL; i < sz; i++) {
    h = darray_get(v->handles, i);
    if (!strcmp(argv[0], h->plugin->command)) {
      if (the_h != NULL) {
	fprintf(stderr, "Multiple plugins for command %s", argv[0]);
	exit(1);
      }
      the_h = h;
    }
  }

  stat = h->plugin->cmdparse(h->obj, argc, argv);
  if (stat != 0)
    fprintf(stderr, "BAT_Validator: %s returned %d.\n", h->plugin->name, stat);

  _BAT_Validator_free_argv(v, argc, argv);

  return 1;
}

/* FIXME: stick this somewhere else when we get a full commandline */
char **
_BAT_Validator_get_argv(BAT_Validator * v, char *cmdline, int *argc)
{
  int largc, arg;
  char *next, *cur, *clcopy;
  char **argv;

  clcopy = malloc((strlen(cmdline) + 1) * sizeof(char));
  strcpy(clcopy, cmdline);
  next = clcopy;
  for (largc = 0; (cur = strsep(&next, " \t\n")); largc++);
  if (largc == 0) {
    fprintf(stderr, "no arguments to command.\n");
    exit(1);
  }
  free(clcopy);

  clcopy = malloc((strlen(cmdline) + 1) * sizeof(char));
  strcpy(clcopy, cmdline);
  argv = malloc(sizeof(char *) * largc);
  for (arg = 0; arg < largc; arg++)
    argv[arg] = strsep(&clcopy, " \t\n");
  *argc = largc;
  return argv;
}

void
_BAT_Validator_free_argv(BAT_Validator * v, int argc, char **argv)
{
  free(*argv);
  free(argv);
}

BAT_GeneTab *
BAT_Validator_validate_gene_table(BAT_Validator * v, BAT_GeneTab * bat)
{
  BAT_Sub_Validator_Handle **handles;
  da_pos_t sz, i;

  handles = (BAT_Sub_Validator_Handle **) darray_get_array(v->handles);
  sz = darray_size(v->handles);

  for (i = 0; i < sz; i++) {
    if (handles[i]->plugin->batv != NULL) {
      v->bat = handles[i]->plugin->batv(handles[i]->obj, bat);
      if (v->bat != bat)
	BAT_GeneTab_delete(bat, 1);
      bat = v->bat;
    }
  }

  /*
   * FIXME: do the rest... need to make sure that if the pointer is
   * updated, we update the bat object...and so on
   */
  /*
   * for(i = 0; i < sz; i++) { if(handles[i]->genev != NULL) { genes =
   * BAT_GeneTab_get_genes(v->bat, &ng); for(g = 0; g < ng; g++) {
   *
   * } }
   */

  return bat;
}
